/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jdbi.doc;

import java.util.List;

import de.softwareforge.testing.postgres.junit5.EmbeddedPgExtension;
import de.softwareforge.testing.postgres.junit5.MultiDatabaseBuilder;
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.core.mapper.reflect.ConstructorMapper;
import org.jdbi.v3.postgres.PostgresPlugin;
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
import org.jdbi.v3.sqlobject.statement.SqlBatch;
import org.jdbi.v3.testing.junit5.JdbiExtension;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import static org.assertj.core.api.Assertions.assertThat;

public class GeneratedKeysTest {

    @RegisterExtension
    public static EmbeddedPgExtension pg = MultiDatabaseBuilder.instanceWithDefaults().build();

    @RegisterExtension
    public JdbiExtension pgExtension = JdbiExtension.postgres(pg)
        .withPlugin(new PostgresPlugin())
        .withPlugin(new SqlObjectPlugin());

    private Jdbi db;

    // tag::setup[]
    public static class User {

        final int id;
        final String name;

        public User(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }

    @BeforeEach
    public void setUp() {
        db = pgExtension.getJdbi();

        db.useHandle(h -> h.execute("CREATE TABLE users (id SERIAL PRIMARY KEY, name VARCHAR)"));
        db.registerRowMapper(ConstructorMapper.factory(User.class));
    }
    // end::setup[]

    @Test
    // tag::fluent[]
    public void fluentInsertKeys() {
        db.useHandle(handle -> {
            User data = handle.createUpdate("INSERT INTO users (name) VALUES(?)")
                    .bind(0, "Data")
                    .executeAndReturnGeneratedKeys()
                    .mapTo(User.class)
                    .one();

            assertThat(data.id).isOne(); // this value is generated by the database
            assertThat(data.name).isEqualTo("Data");
        });
    }
    // end::fluent[]

    @Test
    // tag::sqlObject[]
    public void sqlObjectBatchKeys() {
        db.useExtension(UserDao.class, dao -> {
            List<User> users = dao.createUsers("Alice", "Bob", "Charlie");
            assertThat(users).hasSize(3);

            assertThat(users.get(0).id).isOne();
            assertThat(users.get(0).name).isEqualTo("Alice");

            assertThat(users.get(1).id).isEqualTo(2);
            assertThat(users.get(1).name).isEqualTo("Bob");

            assertThat(users.get(2).id).isEqualTo(3);
            assertThat(users.get(2).name).isEqualTo("Charlie");
        });
    }

    public interface UserDao {
        @SqlBatch("INSERT INTO users (name) VALUES(?)")
        @GetGeneratedKeys
        List<User> createUsers(String... names);
    }
    // end::sqlObject[]
}
